﻿#pragma once


namespace micro{

namespace core
{


class QCriticalSection
{
	CRITICAL_SECTION m_sec;

public:
	QCriticalSection() throw()
	{
		memset(&m_sec, 0, sizeof(CRITICAL_SECTION));
	}
	~QCriticalSection()
	{
	}
	HRESULT Lock() throw()
	{
		EnterCriticalSection(&m_sec);
		return S_OK;
	}
	HRESULT Unlock() throw()
	{
		LeaveCriticalSection(&m_sec);
		return S_OK;
	}
	HRESULT Init() throw()
	{
		HRESULT hRes = E_FAIL;
		__try
		{
			InitializeCriticalSection(&m_sec);
			hRes = S_OK;
		}
		// structured exception may be raised in low memory situations
		__except(STATUS_NO_MEMORY == GetExceptionCode())
		{			
			hRes = E_OUTOFMEMORY;		
		}
		return hRes;
	}

	HRESULT Term() throw()
	{
		DeleteCriticalSection(&m_sec);
		return S_OK;
	}	
	
	
	
};


template< class TLock >
class QCritSecLock
{
public:
	QCritSecLock( TLock& cs, bool bInitialLock = true );
	~QCritSecLock() throw();

	HRESULT Lock() throw();
	void Unlock() throw();

// Implementation
private:
	TLock& m_cs;
	bool m_bLocked;

// Private to avoid accidental use
	QCritSecLock( const QCritSecLock& ) throw();
	QCritSecLock& operator=( const QCritSecLock& ) throw();
};

template< class TLock >
inline QCritSecLock< TLock >::QCritSecLock( TLock& cs, bool bInitialLock ) :
	m_cs( cs ),
	m_bLocked( false )
{
	if( bInitialLock )
	{
		HRESULT hr;

		hr = Lock();
		if( FAILED( hr ) )
		{
			throw( hr );
		}
	}
}

template< class TLock >
inline QCritSecLock< TLock >::~QCritSecLock() throw()
{
	if( m_bLocked )
	{
		Unlock();
	}
}

template< class TLock >
inline HRESULT QCritSecLock< TLock >::Lock() throw()
{
	HRESULT hr;

	ASSERT( !m_bLocked );
	hr = m_cs.Lock();
	if( FAILED( hr ) )
	{
		return( hr );
	}
	m_bLocked = true;

	return( S_OK );
}


template< class TLock >
inline void QCritSecLock< TLock >::Unlock() throw()
{
	ASSERT( m_bLocked );
	m_cs.Unlock();
	m_bLocked = false;
}


 

 



}//core

}//micro